﻿using GrapeCity.Forguncy.Commands;
using GrapeCity.Forguncy.Plugin;
using Neo4JConnector.Core;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Neo4JConnector
{
    [Icon("pack://application:,,,/Neo4JConnector;component/Resources/Icon.png")]
    [Category("neo4j图数据库")]
    [OrderWeight(2)]
    public class QueryShortestPath : BaseNeo4JOp, IServerCommandParamGenerator
    {
        [SearchableProperty]
        [FormulaProperty]
        [DisplayName("节点1的标签")]
        [Description("类似于数据库中的表，用于对节点进行分类。")]
        [OrderWeight(100)]
        public object Label1Expr { get; set; }

        [SearchableProperty]
        [FormulaProperty]
        [DisplayName("节点1的ID")]
        [Description("类似于数据库中的行ID，在同一个表内需要保持唯一。")]
        [OrderWeight(101)]
        public object ID1Expr { get; set; }

        [SearchableProperty]
        [FormulaProperty]
        [DisplayName("节点2的标签")]
        [Description("类似于数据库中的表，用于对节点进行分类。")]
        [OrderWeight(110)]
        public object Label2Expr { get; set; }

        [SearchableProperty]
        [FormulaProperty]
        [DisplayName("节点2的ID")]
        [Description("类似于数据库中的行ID，在同一个表内需要保持唯一。")]
        [OrderWeight(111)]
        public object ID2Expr { get; set; }

        [SearchableProperty]
        [FormulaProperty]
        [DisplayName("寻找路径时采用的关系")]
        [Description("关系的类型名称，如：DependsOn、RelatedTo、PartOf、Requires、Custom1和Custom2。")]
        [OrderWeight(200)]
        public object RelationTypeExpr { get; set; }

        [SearchableProperty]
        [FormulaProperty]
        [DisplayName("关系属性中保存权重的属性")]
        [Description("在关系的属性中，保存有权重的属性的名称。不设置则统一按照1.0计算权重。")]
        [OrderWeight(210)]
        public object WeightExpr { get; set; }

        [DisplayName("将路径保存到变量")]
        [OrderWeight(999)]
        [ResultToProperty]
        public string ResultInParamater { get; set; } = "ShortestPath";

        public override async Task<ExecuteResult> ExecuteAsync(IServerCommandExecuteContext dataContext)
        {
            var id1 = (await dataContext.EvaluateFormulaAsync(ID1Expr))?.ToString() ?? "";
            var id2 = (await dataContext.EvaluateFormulaAsync(ID2Expr))?.ToString() ?? "";
            var label1 = (await dataContext.EvaluateFormulaAsync(Label1Expr))?.ToString() ?? "";
            var label2 = (await dataContext.EvaluateFormulaAsync(Label2Expr))?.ToString() ?? "";

            var relation = (await dataContext.EvaluateFormulaAsync(RelationTypeExpr))?.ToString() ?? "";

            if (string.IsNullOrEmpty(id1) || string.IsNullOrEmpty(id2) || string.IsNullOrEmpty(label1) || string.IsNullOrEmpty(label2) || string.IsNullOrEmpty(relation))
            {
                throw new Exception("节点的标签、ID和关系不能为空。");
            }

            if (!Validators.IsValidLabel(label1) || !Validators.IsValidLabel(label2))
                throw new Exception("节点的标签包含非法字符，仅支持字母数字和下划线，且需要以字母开头。");

            var weight = (await dataContext.EvaluateFormulaAsync(WeightExpr))?.ToString() ?? null;

            var client = await getClient(dataContext);

            var results = await client.ShortestPath(label1, id1, label2, id2, relation, weight, 1.0f, 99);

            if (!string.IsNullOrEmpty(ResultInParamater))
            {
                dataContext.Parameters[ResultInParamater] = results;
            }

            return new ExecuteResult();
        }

        public IEnumerable<GenerateParam> GetGenerateParams()
        {
            yield return new GenerateObjectParam()
            {
                ParamName = this.ResultInParamater,
                Description = "最短路径的计算结果",
                ParamScope = CommandScope.All,
                SubPropertiesDescription = new Dictionary<string, string>() {
                    { "nodes","该路径上的全部节点（含id、lables、properties属性）"},
                    { "relationships","该路径上的全部关系（含type、properties属性）"},
                    { "pathLength","该路径的总长度"},
                    { "totalWeight","该路径的权重合计"}
                }
            };
        }

        public override string ToString()
        {
            return "neo4j：寻找最短路径";
        }
    }
}
